﻿// -----------------------------------------------------------------------
// <copyright file="TextHandler.cs" company="Microsoft">
// Proccessing text data handler
// </copyright>
// -----------------------------------------------------------------------

namespace WebServer.BusinessLogic.Handlers
{
    using System.Text;
    using WebServer.BusinessLogic.Handlers.Interface;
    using WebServer.BusinessLogic.Helpers;
    using WebServer.BusinessLogic.Web;
    using System.Text.RegularExpressions;

    /// <summary>
    /// Handles Text Requests
    /// </summary>
    public class TextHandler : Handler
    {
        /// <summary>
        /// interface for testing
        /// </summary>
        private IFileSystemProvider _fileSystemProvider;

        private ISessionManager _sessionManager;

        /// <summary>
        /// Initializes a new instance of the <see cref="TextHandler" /> class.
        /// </summary>
        /// <param name="fs">fake interface for testing</param>
        public TextHandler(IFileSystemProvider fs) : this()
        {
            this._fileSystemProvider = fs;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="TextHandler" /> class.
        /// </summary>
        /// <param name="fs">fake interface for testing</param>
        /// <param name="sessionManager">fake sessionmanager for testing</param>
        public TextHandler(IFileSystemProvider fs, ISessionManager sessionManager) : this()
        {
            if (sessionManager != null)
            {
                this._sessionManager = sessionManager;
            }
            if (fs != null)
            {
                this._fileSystemProvider = fs;
            }
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="TextHandler" /> class.
        /// </summary>
        public TextHandler()
        {
            this._fileSystemProvider = new FileSystemProvider();
            this._sessionManager = SessionManager.Instance;
        }

        /// <summary>
        /// Tries to handle request.
        /// </summary>
        /// <param name="request">
        /// The request.
        /// </param>
        /// <returns>
        /// The WebServer.BusinessLogic.Response.
        /// </returns>
        public override Response Handle(Request request)
        {
            string ext = request.HttpPath.ToLower();
            if (ext.EndsWith(".html") || ext.EndsWith(".htm") || ext.EndsWith(".css")
                || ext.EndsWith(".js"))
            {
                string filePath = Configurator.Instance.RelativeWwwPath + request.HttpPath.Replace("/", "\\");

                if (!this._fileSystemProvider.FileExists(filePath))
                {
                    return this.NextHandler.Handle(request);
                }

                string cacheKey = request.HttpPath;
                byte[] data = this._fileSystemProvider.GetDataOrFile(cacheKey, filePath);

                // process text (SSI, Admin Panel)
                data = this.ProcessData(data, request);

                // zip and push
                string mimeType = IdentifyContentType(request);
                string version = request.HttpVersion;

                Response toReturn = new Response(mimeType, version, data);
                if (Configurator.Instance.UseResponseCompression && request.AcceptEncoding == EnumAcceptEncoding.Gzip)
                {
                    toReturn.Data = TextHandler.GzipCompress(toReturn.Data);
                    toReturn.ContentEncoding = "gzip";
                }

                return toReturn;
            }

            return this.NextHandler.Handle(request);
        }

        /// <summary>
        /// Processing data with SsiParcer and AdminPanel
        /// </summary>
        /// <param name="data">data  of text file</param>
        /// <param name="request">incoming request</param>
        /// <returns>modified outcoming data for response</returns>
        private byte[] ProcessData(byte[] data, Request request)
        {
            // we have to decode and encode data to insert dynamic content
            string text = Encoding.UTF8.GetString(data);

            var session = _sessionManager.GetCurrentSession(request);
            if (session != null && session.IsAdmin)
            {
                // VK: why is TextHandler handling admin page loading?
                // we've read requested file once, and after that we're AGAIN reading settings.html ...
                // if (request.HttpPath.EndsWith("admin/index.html"))
                // {
                //    string filePath = Configurator.Instance.RelativeWwwPath + "\\admin\\settings.html";
                //    text = File.ReadAllText(filePath);
                // }
                // else
                // {
                text = this.ReplaceWithAdminPanel(text);
                text = this.FixUrlIfSessionEnabled(text, request);
                //// }
            }

            var ssiParser = new SsiParser();
            text = ssiParser.ParseSsi(text, request);

            return Encoding.UTF8.GetBytes(text);
        }

        Regex hrefRegex = new Regex(@"(?<=href\s*=\s*""/)[^""]*(?="")", RegexOptions.Singleline | RegexOptions.Compiled);

        private string FixUrlIfSessionEnabled(string text, Request request)
        {
            string result = text;
            if (_sessionManager.IsCookieless)
            {
                var session = _sessionManager.GetCurrentSession(request);
                if (session != null)
                {
                    result = hrefRegex.Replace(text, delegate(Match match)
                                                              {
                                                                  string href = match.Value;
                                                                  var sessionString = _sessionManager.GetSessionUrl(request);
                                                                  return string.Format("{0}/{1}", sessionString, href);
                                                              });
                }
            }
            return result;
        }

        /// <summary>
        /// Showing that admin is loggined
        /// </summary>
        /// <param name="text">text of text html page</param>
        /// <returns>text with modified body</returns>
        private string ReplaceWithAdminPanel(string text)
        {
            return text.Replace("<body>", string.Format("<body>\r\n[Administrator logged in. <a href=\"{0}\">Logout</a>]<br />\r\n", AdminHandler.AdminLogoutPage.TrimStart(new[] { '/' })));
        }
    }
}
